package com.bridgeintelligent.tag.engine.mvc.service.impl;

import com.bridgeintelligent.tag.engine.api.DimInfo;
import com.bridgeintelligent.tag.engine.api.EngineException;
import com.bridgeintelligent.tag.engine.api.IndexNameInfo;
import com.bridgeintelligent.tag.engine.api.rsp.MultiAnalysisAggregationResult;
import com.bridgeintelligent.tag.engine.core.cache.CacheConfig;
import com.bridgeintelligent.tag.engine.core.cache.CacheUtils;
import com.bridgeintelligent.tag.engine.es.base.ESQueryUtils;
import com.bridgeintelligent.tag.engine.es.model.AnalysisAggregationModel;
import com.bridgeintelligent.tag.engine.es.model.GroupItem;
import com.bridgeintelligent.tag.engine.es.query.EsQueryBuilder;
import com.bridgeintelligent.tag.engine.mvc.service.IEsDateService;
import com.bridgeintelligent.tag.engine.mvc.service.IGroupService;
import com.bridgeintelligent.tag.engine.mvc.service.IMultiAnalysisAggregationService;
import com.bridgeintelligent.tag.engine.mvc.strategy.AbstractAnalysisTemple;
import com.bridgeintelligent.tag.engine.mvc.strategy.AnalysisStrategy;
import com.bridgeintelligent.tag.utils.FieldHandler;
import com.wayneleo.quickstart.framework.ExceptionCode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * xiangjialiang
 */
@Service
@Slf4j
@AllArgsConstructor
public class MultiAnalysisAggreagtionServiceImpl implements IMultiAnalysisAggregationService {

    final private IGroupService groupService;

    final private IEsDateService dateService;

    private static final String CUST_NUM = "cust_num";

    private static final String TERM_SYMBOL = "01|02|06";

    private static final String NUMBER_SYMBOL = "03";

    private static final String DATE_SYMBOL = "05";

    private static final String MOBILE = "mobile_num";

    @Override
    public MultiAnalysisAggregationResult getMultiAnalysisAggregation(AnalysisAggregationModel model) throws IOException {
        //获取XY字段的标签信息
        DimInfo xDimInfo = CacheUtils.getCacheInfo(CacheConfig.DIM_INFO, model.getField());
        DimInfo yDimInfo = CacheUtils.getCacheInfo(CacheConfig.DIM_INFO, model.getYfield());
        if (xDimInfo == null || yDimInfo == null){
            throw new EngineException(new ExceptionCode(999,"未查询到标签"));
        }
        if (StringUtils.equals("04",xDimInfo.getClassify()) || StringUtils.equals("04",yDimInfo.getClassify()) || StringUtils.equals(MOBILE,model.getField()) || StringUtils.equals(MOBILE,model.getYfield())){
            throw new EngineException(new ExceptionCode(999,"不支持该类标签聚合"));
        }
        model.setXDimInfo(xDimInfo);
        model.setYDimInfo(yDimInfo);

        Map<String, String> relation = dateService.symbolRelation(model.getIndexId());
        model.setRelation(relation);

        ignoreField(model,relation);

        //计算类型
        int type = computeType(xDimInfo.getClassify(), yDimInfo.getClassify(), model.getItems(), model.getYitems());
        if (type == 0){
            throw new EngineException(new ExceptionCode(999,"多维度聚合方式未知！"));
        }
        AbstractAnalysisTemple analysisTemple = AnalysisStrategy.create(type, model, groupService);

        MultiAnalysisAggregationResult result = analysisTemple.analysisHandler();
        //计算xy标签同时存在的人数
        String xRealField = FieldHandler.addSuffixField(model.getField(),model.getDataDate(),relation);
        String yRealField = FieldHandler.addSuffixField(model.getYfield(),model.getDataDate(),relation);
        result.setExistCount(this.getMoreExistCount(model,xRealField,yRealField));

        return result;

    }

    public long getMoreExistCount(AnalysisAggregationModel model,String xField, String yField) throws IOException {
        IndexNameInfo indexNameInfo = CacheUtils.getCacheInfo(CacheConfig.CONFIGURATION_INFO, model.getIndexId());
        SearchRequest searchRequest = new SearchRequest(indexNameInfo.getDataDate());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder;
        if (FieldHandler.FALSE.equals(model.getTimeType())){
            queryBuilder = QueryBuilders.boolQuery()
                    .must(EsQueryBuilder.buildFilter(model.getFilterGroup()))
                    .must(QueryBuilders.existsQuery(xField))
                    .must(QueryBuilders.existsQuery(yField));
        }else{
            queryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termsQuery(FieldHandler.CUSTOMER_FLAG,model.getCustomerId()))
                    .must(QueryBuilders.existsQuery(xField))
                    .must(QueryBuilders.existsQuery(yField));
        }
        sourceBuilder.query(queryBuilder).trackTotalHits(true).size(0);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = ESQueryUtils.getClient().search(searchRequest, RequestOptions.DEFAULT);
        if (searchResponse != null){
            SearchHits hits = searchResponse.getHits();
            if (hits != null){
                TotalHits totalHits = hits.getTotalHits();
                if (totalHits != null){
                    return totalHits.value;
                }
            }
        }
        return 0l;
    }

    private void ignoreField(AnalysisAggregationModel model,Map<String, String> relation){

        if (CollectionUtils.isNotEmpty(model.getFields())){
            List<String> list = model.getFields().stream().filter(e -> !e.equals(CUST_NUM)).collect(Collectors.toList());
            model.setFields(list);
            if (!CollectionUtils.isEmpty(list)){
                //获取动态列的时间后缀
                Map map = new HashMap();
                list.forEach(e->{
                    map.put(e, FieldHandler.addSuffixField(e,model.getDataDate(),relation));
                });
                model.setTrendMap(map);
            }
        }
    }

    private int computeType(String xc,String yc, List<GroupItem> xt,List<GroupItem> yt){

        int type = 0;
        if (StringUtils.equals(xc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 1;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 2;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 3;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 4;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 5;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 6;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 7;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 8;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(xt) && TERM_SYMBOL.contains(yc) ){
            type = 9;
        }else if (StringUtils.equals(xc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(xt) && TERM_SYMBOL.contains(yc) ){
            type = 10;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 11;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 12;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 13;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 14;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 15;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 16;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 17;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && !CollectionUtils.isEmpty(xt) && StringUtils.equals(yc,DATE_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 18;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && CollectionUtils.isEmpty(xt) && TERM_SYMBOL.contains(yc) ){
            type = 19;
        }else if (StringUtils.equals(xc,DATE_SYMBOL) && !CollectionUtils.isEmpty(xt) && TERM_SYMBOL.contains(yc) ){
            type = 20;
        }else if ( TERM_SYMBOL.contains(xc) && TERM_SYMBOL.contains(yc) ){
            type = 21;
        }else if ( TERM_SYMBOL.contains(xc) && StringUtils.equals(yc,NUMBER_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 22;
        }else if ( TERM_SYMBOL.contains(xc) && StringUtils.equals(yc,NUMBER_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 23;
        }else if ( TERM_SYMBOL.contains(xc) && StringUtils.equals(yc,DATE_SYMBOL) && CollectionUtils.isEmpty(yt)){
            type = 24;
        }else if ( TERM_SYMBOL.contains(xc) && StringUtils.equals(yc,DATE_SYMBOL) && !CollectionUtils.isEmpty(yt)){
            type = 25;
        }else{
        }
        log.info("X标签：{}，Y标签：{}-----type:{}",xc,yc,type);
        return type;
    }




}
